//
// Created by 贝壳 on 2022/5/26.
//

#include "src/common/stop_watch.h"
#include "src/innodb/page.h"
#include "src/server/Server.h"
#include <string>

#define MAX_PARAMS 10

using namespace std;

struct COMMAND {
    int id;                  // 命令类别
    int argc;                // 参数个数
    string argv[MAX_PARAMS]; // 参数
    COMMAND(int i = 0, int a = 0) {
        id = i;
        argc = a;
    }
};

// 程序运行后，循环读取命令，根据参数调用不同的服务层函数，直到读到终止命令关闭程序

// parse()：将读到的命令根据空格划分为多个参数
COMMAND parse(string line) {
    COMMAND command;
    while (line.find(" ") != string::npos) {
        int found = line.find(" ");
        command.argv[command.argc] = line.substr(0, found);
        command.argc += 1;
        // cout<<"found:"<<command.argv[command.argc-1]<<endl;
        line = line.substr(found + 1);
        // cout<<"line:"<<line<<endl;
    }
    command.argv[command.argc] = line;
    command.argc += 1;

    // 判断命令类型
    if (command.argv[0] == "insert" && command.argc == 6) {
        command.id = 1;
    } else if (command.argv[0] == "insert" && command.argc == 2) {
        command.id = 2;
    } else if (command.argv[0] == "select" && command.argc == 4) {
        command.id = 3;
    } else if (command.argv[0] == "select" && command.argc == 8) {
        command.id = 4;
    } else if (command.argv[0] == "select" && command.argc == 9) {
        command.id = 5;
    } else if (command.argv[0] == "shutdown" && command.argc == 1) {
        command.id = 6;
    } else {
        cout << "error" << endl;
        // id 为0，报错不存在此命令
    }

    return command;
}

void insert(COMMAND command, Server &server) {
    StopWatch stopWatch;
    // 参数类型转换
    int a = atoi(command.argv[1].c_str());
    const unsigned char *c1 = (const unsigned char *) command.argv[2].c_str();
    const unsigned char *c2 = (const unsigned char *) command.argv[3].c_str();
    const unsigned char *c3 = (const unsigned char *) command.argv[4].c_str();
    const unsigned char *c4 = (const unsigned char *) command.argv[5].c_str();
    // 调用服务层函数
    server.insert_value(a, c1, c2, c3, c4);
    cout << ">executed insert index:" << a
         << ", time: " << stopWatch.getElapsedSeconds() << " seconds" << endl;
}

void insertFile(COMMAND command, Server &server) {
    cout << "load data begin.." << endl;
    StopWatch stopWatch;
    // 此处文件名参数，类型为string
    int count = server.insert_from_csv(command.argv[1]);
    if (count == -1) {
        cout << ">file don't exist!" << endl;
        return;
    }
    cout << ">load data end, " << count
         << " rows are inserted, time: " << stopWatch.getElapsedSeconds()
         << " seconds" << endl;
}

void select(COMMAND command, Server &server) {
    StopWatch stopWatch;
    int found = command.argv[3].find("=");
    string condition = command.argv[3].substr(found + 1);
    int con = atoi(condition.c_str());
    int num = 0;     // 实际需要查询的字段个数
    string names[5]; // 字段名
    COMPACT_DATA *compactData = server.search_one_piece(con);
    if (compactData) {
        if (command.argv[1] == "*") {
            cout << "|a|c1|c2|c3|c4|" << endl;
            cout << "|" << compactData->id << "|" << compactData->c1 << "|"
                 << compactData->c2 << "|" << compactData->c3 << "|"
                 << compactData->c4 << "|" << endl;

        } else {
            cout << "|";
            while (command.argv[1].find(",") != string::npos) {
                int found = command.argv[1].find(",");
                names[num] = command.argv[1].substr(0, found);
                cout << names[num] << "|";
                num++;
                command.argv[1] = command.argv[1].substr(found + 1);
            }
            names[num] = command.argv[1];
            cout << names[num] << "|" << endl;
            num++;

            cout << "|";
            for (int i = 0; i < num; i++) {
                if (names[i] == "a")
                    cout << compactData->id << "|";
                else if (names[i] == "c1")
                    cout << compactData->c1 << "|";
                else if (names[i] == "c2")
                    cout << compactData->c2 << "|";
                else if (names[i] == "c3")
                    cout << compactData->c3 << "|";
                else
                    cout << compactData->c4 << "|";
            }
            cout << endl;
            // 此处传入string数组保存字段名，con为查询条件
            // select(string[] names,int con);
        }
        cout << ">executed search, time : " << stopWatch.getElapsedSeconds()
             << " seconds" << endl;
    } else
        cout << ">executed search, not exists, time : "
             << stopWatch.getElapsedSeconds() << " seconds" << endl;
}

void selectBetween(COMMAND command, Server &server) {
    StopWatch stopWatch;
    int value1 = atoi(command.argv[5].c_str());
    int value2 = atoi(command.argv[7].c_str());
    vector<COMPACT_DATA> datas = server.search_in_range(value1, value2);
    cout << "|a|c1|c2|c3|c4|" << endl;
    auto start = datas.begin();
    auto end = datas.end();
    while (start != end) {
        cout << "|" << start->id << "|" << start->c1 << "|" << start->c2 << "|"
             << start->c3 << "|" << start->c4 << "|" << endl;
        start++;
    }
    cout << ">executed search, time : " << stopWatch.getElapsedSeconds()
         << " seconds" << endl;
}

void selectIntoFile(COMMAND command, Server &server) {
    cout << "export data start..." << endl;
    StopWatch stopWatch;
    int value1 = atoi(command.argv[6].c_str());
    int value2 = atoi(command.argv[8].c_str());
    // 此处文件名参数，类型为string
    // selectIntoFile(command.argv[2],value1,value2);
    server.insert_into_csv_in_range(command.argv[2], value1, value2);
    cout << ">export data end, time : " << stopWatch.getElapsedSeconds()
         << " seconds" << endl;
}

void shutdown(Server &server) {
    // 关闭操作
    server.shutdown();
}

int main() {

    string str;
    COMMAND command;
    Server server;

    while (1) {
        if (str == "shutdown") {
            break;
        }
        cout << ">"; // 提示符
        getline(cin, str);
        command = parse(str);

        switch (command.id) {
            case 1:
                // 调用方法1
                insert(command, server);
                break;
            case 2:
                insertFile(command, server);
                break;
            case 3:
                select(command, server);
                break;
            case 4:
                selectBetween(command, server);
                break;
            case 5:
                selectIntoFile(command, server);
                break;
            case 6:
                shutdown(server);
                break;
        }
    }

    return 0;
}